#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
择偶条件服务 - 重构版，支持多选条件、字典验证和智能推荐
"""

from typing import Dict, List, Optional, Any, Tuple
import json
from datetime import datetime
from flask import current_app
from app import db
from app.models.user import User
from app.models.user_profile import UserProfile
from app.models.mate_criteria import MateCriteria
from app.services.dict_service import DictService
from app.services.matching_service import MatchingService


class MateCriteriaService:
    """择偶条件服务层 - 重构版"""
    
    # 择偶条件字段配置
    CRITERIA_FIELDS = {
        # 基础条件
        'min_age': {'type': 'range', 'name': '最小年龄', 'min': 18, 'max': 80},
        'max_age': {'type': 'range', 'name': '最大年龄', 'min': 18, 'max': 80},
        'min_height': {'type': 'range', 'name': '最小身高', 'min': 140, 'max': 220},
        'max_height': {'type': 'range', 'name': '最大身高', 'min': 140, 'max': 220},
        
        # 字典条件（支持多选）
        'education_preferences': {'type': 'multi_dict', 'dict_code': 'education', 'name': '学历偏好'},
        'income_preferences': {'type': 'multi_dict', 'dict_code': 'income_range', 'name': '收入偏好'},
        'occupation_preferences': {'type': 'multi_dict', 'dict_code': 'occupation', 'name': '职业偏好'},
        'marital_preferences': {'type': 'multi_dict', 'dict_code': 'marital_status', 'name': '婚姻状况偏好'},
        'housing_preferences': {'type': 'multi_dict', 'dict_code': 'housing_status', 'name': '住房偏好'},
        'car_preferences': {'type': 'multi_dict', 'dict_code': 'car_status', 'name': '购车偏好'},
        'smoking_preferences': {'type': 'multi_dict', 'dict_code': 'smoking_habit', 'name': '吸烟偏好'},
        'drinking_preferences': {'type': 'multi_dict', 'dict_code': 'drinking_habit', 'name': '饮酒偏好'},
        'personality_preferences': {'type': 'multi_dict', 'dict_code': 'personality_traits', 'name': '性格偏好'},
        
        # 地区偏好（特殊处理）
        'city_preferences': {'type': 'multi_text', 'name': '城市偏好'},
        
        # 其他条件
        'has_children_preference': {'type': 'select', 'name': '对方是否有孩子', 'options': [-1, 0, 1]},  # -1不限，0无，1有
        'wants_children_preference': {'type': 'select', 'name': '对方是否要孩子', 'options': [-1, 0, 1]},
        'other_requirements': {'type': 'text', 'name': '其他要求', 'max_length': 500}
    }
    
    @classmethod
    def get_mate_criteria(cls, user_id: int) -> Optional[Dict[str, Any]]:
        """获取用户择偶条件"""
        try:
            criteria = MateCriteria.query.filter_by(user_id=user_id).first()
            if not criteria:
                return None
            
            criteria_data = criteria.to_dict()
            
            # 解析JSON字段
            for field, config in cls.CRITERIA_FIELDS.items():
                if config['type'] in ['multi_dict', 'multi_text']:
                    value = criteria_data.get(field)
                    if value:
                        try:
                            parsed_value = json.loads(value) if isinstance(value, str) else value
                            criteria_data[field] = parsed_value
                        except (json.JSONDecodeError, TypeError):
                            criteria_data[field] = []
            
            # 添加字典标签显示
            criteria_data['display_labels'] = cls._get_display_labels(criteria_data)
            
            # 添加匹配统计
            criteria_data['match_stats'] = cls._get_criteria_match_stats(user_id, criteria_data)
            
            return criteria_data
            
        except Exception as e:
            current_app.logger.error(f"获取择偶条件异常: {str(e)}")
            return None
    
    @classmethod
    def update_mate_criteria(cls, user_id: int, criteria_data: Dict[str, Any]) -> Dict[str, Any]:
        """更新用户择偶条件（带验证）"""
        try:
            # 检查用户是否存在
            user = User.query.get(user_id)
            if not user:
                return {'success': False, 'error': '用户不存在'}
            
            # 验证择偶条件数据
            validation_result = cls._validate_criteria_data(criteria_data)
            if not validation_result['is_valid']:
                return {
                    'success': False,
                    'error': '数据验证失败',
                    'validation_errors': validation_result['errors']
                }
            
            # 获取或创建择偶条件记录
            criteria = MateCriteria.query.filter_by(user_id=user_id).first()
            if not criteria:
                criteria = MateCriteria(user_id=user_id)
                db.session.add(criteria)
            
            # 更新字段
            updated_fields = []
            for field, config in cls.CRITERIA_FIELDS.items():
                if field in criteria_data:
                    value = criteria_data[field]
                    
                    # 特殊处理多选字段
                    if config['type'] in ['multi_dict', 'multi_text'] and value:
                        if isinstance(value, list):
                            value = json.dumps(value, ensure_ascii=False)
                        elif not isinstance(value, str):
                            value = json.dumps([str(value)], ensure_ascii=False)
                    
                    # 更新字段值
                    old_value = getattr(criteria, field, None)
                    if old_value != value:
                        setattr(criteria, field, value)
                        updated_fields.append(field)
            
            db.session.commit()
            
            # 重新获取更新后的数据
            updated_criteria = cls.get_mate_criteria(user_id)
            
            return {
                'success': True,
                'data': updated_criteria,
                'updated_fields': updated_fields,
                'message': '择偶条件更新成功'
            }
            
        except Exception as e:
            db.session.rollback()
            current_app.logger.error(f"更新择偶条件异常: {str(e)}")
            return {'success': False, 'error': f'更新失败: {str(e)}'}
    
    @classmethod
    def delete_mate_criteria(cls, user_id: int) -> bool:
        """删除用户择偶条件"""
        try:
            criteria = MateCriteria.query.filter_by(user_id=user_id).first()
            if criteria:
                db.session.delete(criteria)
                db.session.commit()
                return True
            return False
        except Exception as e:
            current_app.logger.error(f"删除择偶条件异常: {str(e)}")
            return False
    
    @classmethod
    def get_intelligent_suggestions(cls, user_id: int) -> Dict[str, Any]:
        """获取智能择偶条件建议"""
        try:
            user = User.query.get(user_id)
            if not user:
                return {'success': False, 'error': '用户不存在'}
            
            user_profile = UserProfile.query.filter_by(user_id=user_id).first()
            
            suggestions = {
                'basic_suggestions': cls._get_basic_suggestions(user),
                'preference_suggestions': cls._get_preference_suggestions(user, user_profile),
                'compatibility_suggestions': cls._get_compatibility_suggestions(user_id),
                'popular_preferences': cls._get_popular_preferences()
            }
            
            return {'success': True, 'data': suggestions}
            
        except Exception as e:
            current_app.logger.error(f"获取智能建议异常: {str(e)}")
            return {'success': False, 'error': f'获取失败: {str(e)}'}
    
    @classmethod
    def calculate_criteria_match_score(cls, user_id: int, target_user_id: int) -> Dict[str, Any]:
        """计算择偶条件匹配度"""
        try:
            user_criteria = cls.get_mate_criteria(user_id)
            target_user = User.query.get(target_user_id)
            target_profile = UserProfile.query.filter_by(user_id=target_user_id).first()
            
            if not target_user:
                return {'score': 0, 'details': {}, 'error': '目标用户不存在'}
            
            if not user_criteria:
                return {'score': 50, 'details': {}, 'message': '未设置择偶条件，默认分数'}
            
            # 计算各项匹配分数
            match_details = {}
            total_score = 0
            total_weight = 0
            
            # 年龄匹配
            age_score, age_weight = cls._calculate_age_match(user_criteria, target_user)
            match_details['age'] = {'score': age_score, 'weight': age_weight}
            total_score += age_score * age_weight
            total_weight += age_weight
            
            # 身高匹配
            height_score, height_weight = cls._calculate_height_match(user_criteria, target_user)
            match_details['height'] = {'score': height_score, 'weight': height_weight}
            total_score += height_score * height_weight
            total_weight += height_weight
            
            # 字典条件匹配
            dict_matches = cls._calculate_dict_matches(user_criteria, target_profile)
            for field, match_info in dict_matches.items():
                match_details[field] = match_info
                total_score += match_info['score'] * match_info['weight']
                total_weight += match_info['weight']
            
            # 地区匹配
            city_score, city_weight = cls._calculate_city_match(user_criteria, target_user)
            match_details['city'] = {'score': city_score, 'weight': city_weight}
            total_score += city_score * city_weight
            total_weight += city_weight
            
            # 计算总分
            final_score = (total_score / total_weight) if total_weight > 0 else 0
            
            return {
                'score': round(final_score, 2),
                'details': match_details,
                'match_level': cls._get_match_level(final_score)
            }
            
        except Exception as e:
            current_app.logger.error(f"计算匹配度异常: {str(e)}")
            return {'score': 0, 'details': {}, 'error': f'计算失败: {str(e)}'}
    
    @classmethod
    def find_matches_by_criteria(cls, user_id: int, page: int = 1, per_page: int = 20) -> Dict[str, Any]:
        """根据择偶条件查找匹配用户"""
        try:
            user_criteria = cls.get_mate_criteria(user_id)
            if not user_criteria:
                return {'success': False, 'error': '请先设置择偶条件'}
            
            # 构建查询条件
            query = User.query.filter(User.id != user_id, User.status == 1)
            
            # 年龄筛选
            if user_criteria.get('min_age'):
                query = query.filter(User.age >= user_criteria['min_age'])
            if user_criteria.get('max_age'):
                query = query.filter(User.age <= user_criteria['max_age'])
            
            # 身高筛选
            if user_criteria.get('min_height'):
                query = query.filter(User.height >= user_criteria['min_height'])
            if user_criteria.get('max_height'):
                query = query.filter(User.height <= user_criteria['max_height'])
            
            # 城市筛选
            city_preferences = user_criteria.get('city_preferences', [])
            if city_preferences:
                query = query.filter(User.city.in_(city_preferences))
            
            # 分页查询
            pagination = query.paginate(page=page, per_page=per_page, error_out=False)
            
            # 计算匹配度并排序
            matches = []
            for user in pagination.items:
                match_info = cls.calculate_criteria_match_score(user_id, user.id)
                user_data = user.to_dict()
                user_data['match_score'] = match_info['score']
                user_data['match_level'] = match_info['match_level']
                user_data['match_details'] = match_info['details']
                matches.append(user_data)
            
            # 按匹配度排序
            matches.sort(key=lambda x: x['match_score'], reverse=True)
            
            return {
                'success': True,
                'data': {
                    'matches': matches,
                    'pagination': {
                        'page': pagination.page,
                        'pages': pagination.pages,
                        'per_page': pagination.per_page,
                        'total': pagination.total,
                        'has_next': pagination.has_next,
                        'has_prev': pagination.has_prev
                    }
                }
            }
            
        except Exception as e:
            current_app.logger.error(f"查找匹配用户异常: {str(e)}")
            return {'success': False, 'error': f'查找失败: {str(e)}'}
    
    @classmethod
    def _validate_criteria_data(cls, criteria_data: Dict[str, Any]) -> Dict[str, Any]:
        """验证择偶条件数据"""
        validation_result = {'is_valid': True, 'errors': []}
        
        try:
            for field, value in criteria_data.items():
                if field not in cls.CRITERIA_FIELDS:
                    continue
                
                config = cls.CRITERIA_FIELDS[field]
                
                # 范围类型验证
                if config['type'] == 'range' and value is not None:
                    if not isinstance(value, int) or value < config['min'] or value > config['max']:
                        validation_result['errors'].append(
                            f"{config['name']}应在{config['min']}-{config['max']}之间"
                        )
                        validation_result['is_valid'] = False
                
                # 字典类型验证
                elif config['type'] == 'multi_dict' and value:
                    dict_code = config['dict_code']
                    values = value if isinstance(value, list) else [value]
                    
                    for val in values:
                        if not DictService.validate_dict_value(dict_code, str(val)):
                            validation_result['errors'].append(
                                f"{config['name']}包含无效值: {val}"
                            )
                            validation_result['is_valid'] = False
                
                # 选择类型验证
                elif config['type'] == 'select' and value is not None:
                    if value not in config['options']:
                        validation_result['errors'].append(
                            f"{config['name']}值无效，可选值: {config['options']}"
                        )
                        validation_result['is_valid'] = False
                
                # 文本长度验证
                elif config['type'] == 'text' and value:
                    if len(str(value)) > config.get('max_length', 500):
                        validation_result['errors'].append(
                            f"{config['name']}长度不能超过{config.get('max_length', 500)}字符"
                        )
                        validation_result['is_valid'] = False
            
            # 年龄范围逻辑验证
            min_age = criteria_data.get('min_age')
            max_age = criteria_data.get('max_age')
            if min_age and max_age and min_age > max_age:
                validation_result['errors'].append('最小年龄不能大于最大年龄')
                validation_result['is_valid'] = False
            
            # 身高范围逻辑验证
            min_height = criteria_data.get('min_height')
            max_height = criteria_data.get('max_height')
            if min_height and max_height and min_height > max_height:
                validation_result['errors'].append('最小身高不能大于最大身高')
                validation_result['is_valid'] = False
            
            return validation_result
            
        except Exception as e:
            return {
                'is_valid': False,
                'errors': [f'验证失败: {str(e)}']
            }
    
    @classmethod
    def _get_display_labels(cls, criteria_data: Dict[str, Any]) -> Dict[str, Any]:
        """获取显示标签"""
        labels = {}
        
        try:
            for field, config in cls.CRITERIA_FIELDS.items():
                if config['type'] == 'multi_dict' and field in criteria_data:
                    values = criteria_data.get(field, [])
                    if values:
                        dict_code = config['dict_code']
                        labels[field] = [
                            DictService.get_dict_item_label(dict_code, val) or val
                            for val in values
                        ]
                
                elif config['type'] == 'select' and field in criteria_data:
                    value = criteria_data.get(field)
                    if value == -1:
                        labels[field] = '不限'
                    elif value == 0:
                        labels[field] = '无' if 'children' in field else '否'
                    elif value == 1:
                        labels[field] = '有' if 'children' in field else '是'
            
            return labels
            
        except Exception as e:
            current_app.logger.error(f"获取显示标签异常: {str(e)}")
            return {}
    
    @classmethod
    def _get_criteria_match_stats(cls, user_id: int, criteria_data: Dict[str, Any]) -> Dict[str, Any]:
        """获取择偶条件匹配统计"""
        # 这里可以实现统计当前择偶条件能匹配到多少用户
        # 暂时返回模拟数据
        return {
            'total_matches': 0,
            'high_matches': 0,
            'medium_matches': 0,
            'low_matches': 0
        }
    
    @classmethod
    def _get_basic_suggestions(cls, user: User) -> Dict[str, Any]:
        """获取基础条件建议"""
        suggestions = {}
        
        # 年龄建议
        if user.age:
            suggestions['min_age'] = max(18, user.age - 5)
            suggestions['max_age'] = min(80, user.age + 8)
        
        # 身高建议
        if user.height:
            if user.gender == 1:  # 男性
                suggestions['min_height'] = max(140, user.height - 20)
                suggestions['max_height'] = 180
            else:  # 女性
                suggestions['min_height'] = 150
                suggestions['max_height'] = min(220, user.height + 20)
        
        return suggestions
    
    @classmethod
    def _get_preference_suggestions(cls, user: User, profile: Optional[UserProfile]) -> Dict[str, Any]:
        """获取偏好建议"""
        suggestions = {}
        
        if user.city:
            suggestions['city_preferences'] = [user.city]
        
        if profile:
            # 根据用户资料推荐相似的偏好
            if profile.education:
                suggestions['education_preferences'] = [profile.education]
            
            if profile.income_range:
                suggestions['income_preferences'] = [profile.income_range]
        
        return suggestions
    
    @classmethod
    def _get_compatibility_suggestions(cls, user_id: int) -> Dict[str, Any]:
        """获取兼容性建议"""
        # 基于用户行为数据的建议（暂时返回空）
        return {}
    
    @classmethod
    def _get_popular_preferences(cls) -> Dict[str, Any]:
        """获取热门偏好"""
        # 基于平台数据的热门偏好（暂时返回模拟数据）
        return {
            'education_preferences': ['本科', '硕士'],
            'income_preferences': ['10-20万', '20-50万'],
            'city_preferences': ['北京', '上海', '广州', '深圳']
        }
    
    @classmethod
    def _calculate_age_match(cls, criteria: Dict, target_user: User) -> Tuple[float, float]:
        """计算年龄匹配分数"""
        if not target_user.age:
            return 50.0, 0.2  # 无年龄信息，中等分数
        
        min_age = criteria.get('min_age')
        max_age = criteria.get('max_age')
        
        if not min_age and not max_age:
            return 100.0, 0.2  # 无年龄要求，满分
        
        age = target_user.age
        
        # 在范围内得满分
        if (not min_age or age >= min_age) and (not max_age or age <= max_age):
            return 100.0, 0.2
        
        # 超出范围计算距离惩罚
        penalty = 0
        if min_age and age < min_age:
            penalty = min_age - age
        elif max_age and age > max_age:
            penalty = age - max_age
        
        score = max(0, 100 - penalty * 10)  # 每超出1岁扣10分
        return score, 0.2
    
    @classmethod
    def _calculate_height_match(cls, criteria: Dict, target_user: User) -> Tuple[float, float]:
        """计算身高匹配分数"""
        if not target_user.height:
            return 50.0, 0.1
        
        min_height = criteria.get('min_height')
        max_height = criteria.get('max_height')
        
        if not min_height and not max_height:
            return 100.0, 0.1
        
        height = target_user.height
        
        if (not min_height or height >= min_height) and (not max_height or height <= max_height):
            return 100.0, 0.1
        
        penalty = 0
        if min_height and height < min_height:
            penalty = min_height - height
        elif max_height and height > max_height:
            penalty = height - max_height
        
        score = max(0, 100 - penalty * 2)  # 每超出1cm扣2分
        return score, 0.1
    
    @classmethod
    def _calculate_dict_matches(cls, criteria: Dict, target_profile: Optional[UserProfile]) -> Dict[str, Dict]:
        """计算字典条件匹配"""
        matches = {}
        
        dict_field_mapping = {
            'education_preferences': 'education',
            'income_preferences': 'income_range',
            'occupation_preferences': 'occupation',
            'marital_preferences': 'marital_status',
            'housing_preferences': 'housing_status',
            'car_preferences': 'car_status',
            'smoking_preferences': 'smoking_habit',
            'drinking_preferences': 'drinking_habit'
        }
        
        for criteria_field, profile_field in dict_field_mapping.items():
            preferences = criteria.get(criteria_field, [])
            
            if not preferences:
                matches[criteria_field] = {'score': 100.0, 'weight': 0.1}
                continue
            
            target_value = getattr(target_profile, profile_field, None) if target_profile else None
            
            if not target_value:
                matches[criteria_field] = {'score': 50.0, 'weight': 0.1}
                continue
            
            # 检查是否在偏好列表中
            if target_value in preferences:
                matches[criteria_field] = {'score': 100.0, 'weight': 0.15}
            else:
                matches[criteria_field] = {'score': 0.0, 'weight': 0.15}
        
        return matches
    
    @classmethod
    def _calculate_city_match(cls, criteria: Dict, target_user: User) -> Tuple[float, float]:
        """计算城市匹配分数"""
        city_preferences = criteria.get('city_preferences', [])
        
        if not city_preferences:
            return 100.0, 0.1
        
        if not target_user.city:
            return 50.0, 0.1
        
        if target_user.city in city_preferences:
            return 100.0, 0.15
        else:
            return 30.0, 0.15  # 不在偏好城市，给一定基础分
    
    @classmethod
    def _get_match_level(cls, score: float) -> str:
        """获取匹配等级"""
        if score >= 80:
            return '高度匹配'
        elif score >= 60:
            return '中等匹配'
        elif score >= 40:
            return '一般匹配'
        else:
            return '匹配度较低' 